/**
 * Created by cchen on 2015/5/19.
 */
Date.prototype.format = function (format) {
    var o = {
        "M+": this.getMonth() + 1, //month
        "d+": this.getDate(), //day
        "h+": this.getHours(), //hour
        "m+": this.getMinutes(), //minute
        "s+": this.getSeconds(), //second
        "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
        "S": this.getMilliseconds() //millisecond
    }
    if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
        (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o) if (new RegExp("(" + k + ")").test(format))
        format = format.replace(RegExp.$1,
            RegExp.$1.length == 1 ? o[k] :
                ("00" + o[k]).substr(("" + o[k]).length));
    return format;
}
if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match;
        });
    };
}

function newIncrementDate(startDate, dayIncrement) {
    var tempDate = new Date(startDate)
    var newDate = new Date(tempDate.setDate(tempDate.getDate() + dayIncrement));
    return newDate
}

function convertDictToList(dict) {
    var list = []
    for (i in dict)
        list.push(i)
    return list;
}

function generateWeeksList(startDate, endDate) {
    var start = new Date(startDate)
    var end = new Date(endDate);
    var msDay = 60 * 60 * 24 * 1000
    var list = []

    var day_difference = Math.floor((end - start) / msDay)

    for (var i = 0; i <= day_difference; i++) {
        if (i % 7 == 0) {
            var tempdate = new Date(start)
            var newweek = new Date(tempdate.setDate(tempdate.getDate() + i));
            list.push(newweek.format("yyyy-MM-dd"))
        }
    }
    return list
}
function startAndEndOfWeek(date) {

    var now = date ? new Date(date) : new Date();

    now.setHours(0, 0, 0, 0);

    // Get the previous Monday
    var monday = new Date(now);
    monday.setDate(monday.getDate() - monday.getDay() + 1);

    // Get next Sunday
    var sunday = new Date(now);
    sunday.setDate(sunday.getDate() - sunday.getDay() + 7);

    return [monday.format('yyyy-MM-dd'), sunday.format('yyyy-MM-dd')];
}

function generateMonthsList(startDate, endDate) {

    var monthList = []

    var startMonth = parseInt(startDate.toString().split('-')[1])
    var endMonth = parseInt(endDate.toString().split('-')[1])

    var startYear = parseInt(startDate.toString().split('-')[0])
    var endYear = parseInt(endDate.toString().split('-')[0])
    //
    var monthDiff = endMonth - startMonth + (endYear - startYear) * 12

    for (var i = 0; i <= monthDiff; i++) {
        var newDate = new Date(startDate).setMonth(new Date(startDate).getMonth() + i);
        monthList.push(new Date(newDate).format('yyyy-MM-dd'))
    }
    return monthList
}
function getDayDiff(startDate, endDate) {
    var start = new Date(startDate)
    var end = new Date(endDate);
    var msDay = 60 * 60 * 24 * 1000
    var daydiff = Math.abs(Math.floor((end - start) / msDay))
    return start < end ? -daydiff : daydiff
}

function sortOnKeys(dict) {

    var sorted = [];
    for(var key in dict) {
        sorted[sorted.length] = key;
    }
    sorted.sort();

    var tempDict = {};
    for(var i = 0; i < sorted.length; i++) {
        tempDict[sorted[i]] = dict[sorted[i]];
    }

    return tempDict;
}


var onlineDate = '2015-03-02'

/** GRAPH and GRAPH FUNCTIONS */

var dataGraph = {}  // Graph global variable    e.g. dataGraph = {users: {data: {chart:{renderTo:'usersChart'}, ...}}, {question: {data: {chart:{renderTo:'questionChart'},...}} ,...}

function createStackedColumnGraphTemplate() {
    var columnGraphTemplate = {
        chart: {
            renderTo: '',
            type: 'column'
        },
        title: {
            text: ''
        },
        subtitle: {
            text: ''
        },
        xAxis: {
            categories: []
        },
        yAxis: {
            min: 0,
            title: {
                text: ''
            },
            stackLabels: {
                enabled: true,
                style: {
                    fontWeight: 'bold',
                    color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
                }
            }
        },
        legend: {
            align: 'right',
            x: -30,
            verticalAlign: 'top',
            y: 25,
            floating: true,
            backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
            borderColor: '#CCC',
            borderWidth: 1,
            shadow: false
        },
        tooltip: {
            formatter: function () {
                return '<b>' + this.x + '</b><br/>' +
                    this.series.name + ': ' + this.y + '<br/>' +
                    'Total: ' + this.point.stackTotal;
            }
        },
        plotOptions: {
            column: {
                stacking: 'normal',
                dataLabels: {
                    enabled: true,
                    color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
                    style: {
                        textShadow: '0 0 3px black'
                    }
                }
            }
        },
        series: []
    }
    return columnGraphTemplate
}

function createComboGraphTemplate() {
    var graphTemplate = {
        chart: {
            renderTo: '',
            zoomType: 'xy'
        },
        title: {
            text: ''
        },
        subtitle: {
            text: ''
        },
        xAxis: [{
            categories: [],
            crosshair: true
        }],
        yAxis: [
            { // Primary yAxis: retentionRate %
                title: {
                    text: '',
                    style: {}
                },
                labels: {
                    format: '{value}%',
                    style: {}
                }
            }, { // Secondary yAxis: 用户数
                title: {
                    text: '',
                    style: {}
                },
                labels: {
                    format: '{value}',
                    style: {}
                },
                opposite: true
            }],
        tooltip: {
            shared: false
        },
        legend: {},
        series: []
    }

    return graphTemplate
}

function pushXAxisCategoryToGraph(graph, category) {
    dataGraph[graph].data.xAxis.categories.push(category)
}

function clearXAxisCategoryInGraph(graph) {
    dataGraph[graph].data.xAxis.categories = []
}

function pushDataToGraph(graph, seriesName, seriesDataArray) {
    var graphRef = dataGraph[graph].data

    var len = graphRef.series.length
    for (var i = 0; i < len; i++) {
        if (seriesName === graphRef.series[i].name) {
            if (Object.prototype.toString.call(seriesDataArray) === '[object Array]') {
                seriesDataArray.forEach(function (item) {
                    graphRef.series[i].data.push(item)
                })
            }
            return
        }
    }
    var newSeries = {name: seriesName, color: getGraphSeriesColor(len), data: []}
    if (Object.prototype.toString.call(seriesDataArray) === '[object Array]') {
        seriesDataArray.forEach(function (item) {
            newSeries.data.push(item)
        })
    }
    graphRef.series.push(newSeries)
}

function displayGraph(graphRef) {
    dataGraph[graphRef].chart = new Highcharts.Chart(dataGraph[graphRef].data)
}

function getGraphSeriesColor(idx) {
    return Highcharts.getOptions().colors[idx];
}
function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}


'use strict';
angular.module('backofficeApp.reportManager.controller', []).
    controller('reportListCtrl', ['$scope', '$http', function ($scope, $http) {
        $http.get("/rest/v1.0/backoffice/activity/reports")
            .success(function (res) {
                var html = "";
                for (var i = 0; i < res.data.length; i++) {
                    html += "<li><span>" + res.data[i].nickName + "</span><br><span>" + res.data[i].desc + "</span></li>";
                }
                $("#report_list").html(html);
                //var is = new iScroll("reports", { "useTransition": true, "vScrollbar": false, "hScroll": false, "onScrollStart": function () {
                //    //scrollControl = true;
                //}});
                //is.refresh();
            });
    }])
    .controller('clickSourceReportingCtrl', ['$scope', '$http', function ($scope, $http) {

        $scope.date = new Date()

        $scope.clickSourceData = []

        $scope.getClickSource = function (start, end) {
            var startDate = start == null || start == '' ? 'all' : start
            var endDate = end == null || end == '' ? 'all' : end

            $('#loadingText').html('Loading...')

            if (startDate === 'all')
                $('#startDateText').html('开始')
            else
                $('#startDateText').html(startDate)

            if (endDate === 'all')
                $('#endDateText').html(new Date().format('yyyy-MM-dd hh:mm:ss'))
            else
                $('#endDateText').html(endDate)
            getClickSourceDataAPI(startDate, endDate)
        }

        function getClickSourceDataAPI(startDate, endDate) {
            $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getClickSource/' + startDate + '/' + endDate, {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                $scope.clickSourceData = data.data
                $('#loadingText').html('')
            }).error(function () {
            });
        }

        // Init page
        $scope.getClickSource('all', 'all')

        // Sort columns
        $scope.orderByField = 'total';
        $scope.reverseSort = true;

    }]).
    controller('marketingReportingCtrl', ['$scope', '$http', function ($scope, $http) {

        $scope.communityList = []

        function getCommListAPI() {
            $http.get('http://' + backOfficeHost + '/rest/v1.0/communities/getAllCommunityFromSQL', {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                var len = data.data.length
                for (var i = 0; i < len; i++) {
                    if (data.data[i].isValid == 'True')
                        $scope.communityList.push(data.data[i])
                }
            }).error(function () {
            });
        }

        getCommListAPI()

        $scope.inviteList = []
        $scope.inviteSentList = []

        $scope.refreshInviteList = function (community) {
            getinviteListAPI(community)
        }

        var inviteSentPageLoaded = false;

        $scope.initInviteSentList = function (community) {
            if (!inviteSentPageLoaded)
                getInviteSentListAPI(community)
            inviteSentPageLoaded = true
        }
        $scope.refreshInviteSentList = function (community) {
            getInviteSentListAPI(community)
        }

        $scope.exportInviteListData = function () {
            var blob = new Blob([document.getElementById('exportable1').innerHTML], {
                type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
            });
            saveAs(blob, "InviteList.xls");
        }


        function getinviteListAPI(community) {
            $('#loadingInviteText').html("Loading...")

            if (community == null)
                community = 'all'

            //$scope.inviteList = []
            $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getMarketingInviteList/' + community, {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                $scope.inviteList = data.data
                $('#loadingInviteText').html('')
            }).error(function () {
            });
        }

        getinviteListAPI('all')

        $scope.orderByField = 'invitationSent';
        $scope.reverseSort = true;

        function getInviteSentListAPI(community) {
            $('#loadingInviteSentText').html("Loading...")

            if (community == null)
                community = 'all'

            //$scope.inviteSentList = []
            $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getMarketingInviteSentList/' + community, {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                $scope.inviteSentList = data.data
                $('#loadingInviteSentText').html('')
            }).error(function () {
            });
        }

        $scope.exportInviteSentListData = function () {
            var blob = new Blob([document.getElementById('exportable2').innerHTML], {
                type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
            });
            saveAs(blob, "InviteSentList.xls");
        }
        //getInviteSentListAPI('all')

        //$scope.printOut = function(){
        //    console.log($scope.communityList)
        //}

    }]).controller('reportingCtrl', ['$scope', '$http', '$compile', function ($scope, $http, $compile) {

        /** CACHE: This is the heart of the web page
         *
         *  数据结构: { comm1:{date1:{users:10,vusers:5,questions:30,newusers:{day:1, week:4},...},date2:{users:20,...},...}, comm2:{date1:{users:30,...},...}, comm3:{}, ...}
         *  e.g. $scope.reportingData[comm1][date2][users] = 20
         *  e.g. $scope.reportingData[comm1][date1][newusers][week] = 4
         */
        $scope.reportingData = {}


        /**  ========= DISTRICT 大区 =========  */
        $scope.districtList = []

        var districtIndex = {}

        $scope.getDistrictComms = function (district) {
            if (districtIndex[district] != null)
                return
            districtIndex[district] = {}
            var len = $scope.communityList.length
            for (var i = 0; i < len; i++) {
                var grps = $scope.communityList[i].groups
                if (grps != null && grps.length != 0) {
                    var grpslen = grps.length
                    for (var g = 0; g < grpslen; g++) {
                        if (grps[g] == district) {
                            var community = $scope.communityList[i].objId
                            districtIndex[district][community] = $scope.communityList[i].communityName
                            var len2 = $scope.displayedColumns.length;
                            for (var d = 0; d < len2; d++)
                                $scope.getReport(community, $scope.date, $scope.displayedColumns[d])
                        }
                    }
                }
            }
        }


        /**  ========= COMMUNITY 小区 LIST =========  */
        $scope.communityList = []
        function getCommListAPI() {
            $http.get('http://' + backOfficeHost + '/rest/v1.0/communities/getAllCommunityFromSQL', {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                var len = data.data.length
                for (var i = 0; i < len; i++) {
                    if (data.data[i].isValid == 'True')
                        $scope.communityList.push(data.data[i])
                }
            }).error(function () {
            });
        }

        getCommListAPI()

        var allCommName = '全部'

        $scope.weeklyColumn = generateWeeksList(onlineDate, new Date())
        $scope.monthlyColumn = generateMonthsList(onlineDate, new Date().format('yyyy-MM-dd').toString())


        /** ==================================== MAIN PAGE (GRAPHS) ====================================  */

        var graphColumns = ['users', /*'vusers',*/ 'question', 'questionusers', 'replies', 'repliesusers']
        $scope.commsInGraph = {}


        var sd = null
        var ed = null
        $scope.getGraph = function (community, startDate, endDate) {

            if (community == null)
                community = 'all'

            var today = new Date().format('yyyy-MM-dd')

            if (startDate == null || startDate == '')
                startDate = onlineDate
            if (endDate == null || endDate == '')
                endDate = today

            var resetAllData = false

            if (startDate != sd || endDate != ed)
                resetAllData = true
            else if (community in $scope.commsInGraph)
                return
            $scope.commsInGraph[community] = getCommName(community)
            sd = startDate
            ed = endDate

            if ($scope.reportingData[community] == null)
                $scope.reportingData[community] = {}

            var weekStartDateList = generateWeeksList(startAndEndOfWeek(startDate)[0], endDate)
            var weekEndDateList = generateWeeksList(startAndEndOfWeek(startDate)[1], endDate)
            if (weekEndDateList.indexOf(today) == -1)
                weekEndDateList.push(today)

            // LOAD GRAPH DATA AND DISPLAY GRAPH
            $("#loadingMainText").html("Loading Graph...")
            if (resetAllData) {
                graphFunctions.xAxis.pushTimeCategoryToMainGraphs(graphColumns, weekStartDateList)      // display startOfWeek dates at graph xAxis. data points are endOfWeek
                graphFunctions.series.resetAllDataInMainGraphs()
                getCommsInGraphData(weekEndDateList)
            } else {
                if (checkIfMainGraphCommDataExists(community, weekEndDateList)) {
                    graphColumns.forEach(function (datatype) {
                        pushDataToMainGraph(community, datatype, weekEndDateList)
                    })
                    $("#loadingMainText").html("")
                    $scope.refreshMainGraphs()
                } else {
                    var promise = getCommGraphDataAPI(community)
                    promise.then(function (data) {
                        graphColumns.forEach(function (datatype) {
                            pushDataToMainGraph(community, datatype, weekEndDateList)
                        })
                        $("#loadingMainText").html("")
                        $scope.refreshMainGraphs()
                    })
                }
            }
        }

        function getCommsInGraphData(weekEndDateList) {
            var count = 0
            var len = Object.keys($scope.commsInGraph).length
            for (comm in $scope.commsInGraph) {
                count++
                if (checkIfMainGraphCommDataExists(comm, weekEndDateList)) {
                    graphColumns.forEach(function (datatype) {
                        pushDataToMainGraph(comm, datatype, weekEndDateList)
                    })
                    if (count == len) {
                        $("#loadingMainText").html("")
                        $scope.refreshMainGraphs()
                        count = 0
                    }
                } else {
                    var promise = getCommGraphDataAPI(comm)
                    promise.then(function (data) {
                        graphColumns.forEach(function (datatype) {
                            pushDataToMainGraph(comm, datatype, weekEndDateList)
                        })
                        if (count == len) {
                            $("#loadingMainText").html("")
                            $scope.refreshMainGraphs()
                            count = 0
                        }
                    })
                }
            }
        }

        function getCommGraphDataAPI(comm) {
            var promise = $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getCommunityMainStatsReport/' + comm, {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).then(function (data) {
                for (datatype in data.data.data) {
                    var array = data.data.data[datatype]
                    var len = array.length;
                    var totalCount = 0;
                    for (var i = 0; i < len; i++) {
                        totalCount += array[i]['count']
                        var weekEnding = array[i]['weekEnding']
                        if (i == len - 1 && weekEnding > new Date().format('yyyy-MM-dd'))    // shift to today's date as latest date
                            weekEnding = new Date().format('yyyy-MM-dd')
                        if ($scope.reportingData[comm][weekEnding] == null)
                            $scope.reportingData[comm][weekEnding] = {}
                        $scope.reportingData[comm][weekEnding][datatype] = datatype == 'users' ? Math.floor(totalCount * 0.9) : totalCount
                    }
                }
                return 'success'
            })
            return promise
        }


        function pushDataToMainGraph(community, datatype, weekEndDateList) {
            var idx = 0
            var totalCount = 0
            weekEndDateList.forEach(function (weekEnding) {
                if ($scope.reportingData[community][weekEnding] == null) {
                    $scope.reportingData[community][weekEnding] = {}
                    $scope.reportingData[community][weekEnding][datatype] = totalCount
                } else if ($scope.reportingData[community][weekEnding][datatype] == null) {
                    $scope.reportingData[community][weekEnding][datatype] = totalCount
                } else {
                    totalCount = $scope.reportingData[community][weekEnding][datatype]
                }
                pushDataToGraph(datatype, $scope.commsInGraph[community], [[idx, $scope.reportingData[community][weekEnding][datatype]]])
                idx++
            })
        }

        function checkIfMainGraphCommDataExists(comm, weekEndDateList) {
            var lenGraphs = graphColumns.length;
            var lenWeeks = weekEndDateList.length;
            for (var i = 0; i < lenWeeks; i++) {
                var weekEnding = weekEndDateList[i]
                if ($scope.reportingData[comm][weekEnding] == null) {
                    return false
                } else {
                    for (var j = 0; j < lenGraphs; j++) {       // check if all datatypes exist within each week in datastructure
                        var datatype = graphColumns[j]
                        if ($scope.reportingData[comm][weekEnding][datatype] == null) {
                            return false
                        }
                    }
                }
            }
            return true
        }

        $scope.refreshMainGraphs = function () {
            var len = graphColumns.length
            for (var i = 0; i < len; i++) {
                displayGraph(graphColumns[i])
            }
        }

        $scope.removeCommInGraphs = function (community) {
            graphFunctions.series.removeCommInMainGraphs(community)
            delete $scope.commsInGraph[community]
            $scope.refreshMainGraphs()
        }

        var graphFunctions = {
            initMainGraphs: function () {
                var len = graphColumns.length;
                for (var i = 0; i < len; i++) {
                    this.createMainGraphObject(graphColumns[i])
                    $('#chartDisplay').append('<div id="' + graphColumns[i] + 'Chart" style="height: 400px; width: 70%; display: block; margin: auto;"></div>')
                }
            },
            createMainGraphObject: function (graphObj) {
                dataGraph[graphObj] = {data: createStackedColumnGraphTemplate()}

                var graphName = graphObj + 'Chart'
                dataGraph[graphObj].data.chart.renderTo = graphName

                var titleName = this.title.getMainGraphTitleName(graphObj)
                dataGraph[graphObj].data.title.text = titleName
                if (graphObj === 'users')
                    dataGraph[graphObj].data.subtitle.text = '(不包括400/500/600/700小号)\n'
                dataGraph[graphObj].data.subtitle.text += 'End of Week'
                dataGraph[graphObj].data.yAxis.title.text = titleName

            },
            series: {
                resetCommDataInMainGraphs: function (community) {
                    var len = graphColumns.length
                    for (var i = 0; i < len; i++) {
                        for (s in dataGraph[graphColumns[i]].data.series) {
                            if (dataGraph[graphColumns[i]].data.series[s].name == getCommName(community)) {
                                dataGraph[graphColumns[i]].data.series[s].data = []
                                break
                            }
                        }
                    }
                },
                resetAllDataInMainGraphs: function () {
                    var len = graphColumns.length
                    for (var i = 0; i < len; i++) {
                        if (dataGraph[graphColumns[i]].data === 'undefined')
                            return false
                        for (s in dataGraph[graphColumns[i]].data.series) {
                            dataGraph[graphColumns[i]].data.series[s].data = []
                        }
                    }
                },
                removeCommInMainGraphs: function (community) {
                    var len = graphColumns.length
                    for (var i = 0; i < len; i++) {
                        for (s in dataGraph[graphColumns[i]].data.series) {
                            if (dataGraph[graphColumns[i]].data.series[s].name == getCommName(community)) {
                                dataGraph[graphColumns[i]].data.series.splice(s, 1)
                                break
                            }
                        }
                    }
                },
                colorSeriesInMainGraphs: function (community) {
                    var color = getRandomColor()
                    var len = graphColumns.length
                    for (var i = 0; i < len; i++) {
                        for (s in dataGraph[graphColumns[i]].data.series) {
                            if (dataGraph[graphColumns[i]].data.series[s].name == getCommName(community)) {
                                dataGraph[graphColumns[i]].data.series.color = color;
                                break
                            }
                        }
                    }
                }
            },
            xAxis: {
                pushTimeCategoryToMainGraphs: function (graphs, timeSeries) {
                    var glen = graphs.length;
                    for (var c = 0; c < glen; c++) {
                        clearXAxisCategoryInGraph(graphs[c])
                        var tlen = timeSeries.length
                        for (var t = 0; t < tlen; t++)
                            pushXAxisCategoryToGraph(graphs[c], timeSeries[t])
                    }
                }
            }
            ,
            title: {
                getMainGraphTitleName: function (datatype) {
                    var titleName = ''
                    for (t in $scope.columns) {
                        var dt = t.split('$')[2]
                        if (datatype === dt) {
                            titleName = $scope.columns[t]
                            break
                        }
                    }
                    return titleName
                }
            }
        }


        /** =========================================  STATS PAGE  ========================================= */

        $scope.date = new Date().format("yyyy-MM-dd")
        var interval = 7
        var intervaltext = interval == 7 ? 'week' : 'day'

        var communityCount = -1;
        var communityIndex = {}

        /** ======= COLUMNS: Week, Data, Displayed Columns  ======== */
        $scope.columns = {
            // table$returntype$datatype, e.g. returntype: total = count(*), distinct_id = count(distinct id)
            users$distinct__id$users: '总用户数',
            //users$distinct__id$vusers: '总V用户数',
            users$distinct__id$newusers: '新增用户数',
            //users$distinct__id$newvusers: '新增V用户数',
            question$total$question: '发布数',
            question$distinct_createdBy$questionusers: '发布人数',
            question$total$newquestion: '新增发布数',
            reply$total$replies: '回复数',
            reply$distinct_repliedBy$repliesusers: '回复人数',
            reply$total$newreplies: '新增回复数',
            dau$total$activeusers: '活跃度'
        }

        $scope.column2 = {
            dau$total$dau: '日活跃度', none$activity$WAU: '周活跃度',
        }

        $scope.displayedColumns = convertDictToList($scope.columns)     // checked columns


        function initCommunityDisplay(comm, date) {
            var districtName = ''
            var commName = ''
            if (comm == 'all') {
                districtName = allCommName
                commName = allCommName
            } else {
                var len = $scope.communityList.length
                for (var i = 0; i < len; i++) {
                    if ($scope.communityList[i].objId == comm) {
                        if ($scope.communityList[i].groups != null && $scope.communityList[i].groups.length > 0) {
                            var grpslen = $scope.communityList[i].groups.length;
                            for (var g = 0; g < grpslen; g++) {
                                for (var j = 0; j < $scope.districtList.length; j++) {
                                    if ($scope.districtList[j].objId == $scope.communityList[i].groups[g]) {
                                        districtName += $scope.districtList[j].groupName
                                        break;
                                    }
                                }
                            }
                        }
                        commName = $scope.communityList[i].communityName
                        break
                    }
                }
            }
            $("#datadisplay").append("<tr id='" + comm + "'></tr>")
            //$("#" + comm).append('<td><button class="glyphicon glyphicon-remove" onclick="removeRow(this)"></button></td>')
            $("#" + comm).append("<td style='font-size: 13px'>" + districtName + "</td>")
            $("#" + comm).append("<td style='font-weight: bold; font-size: 13px'>" + commName + "</td>")
            $("#" + comm).append("<td id='date" + communityIndex[comm] + "'>" + date + "</td>")
        }

        $scope.getReport = function (community, date, column) {

            if (community == null && column == null) return
            if (community in communityIndex && column == null) return
            community = community == null ? 'all' : community

            var date = date == null ? new Date().format("yyyy-MM-dd") : date
            $scope.date = date

            if (communityIndex[community] == null) {
                communityIndex[community] = ++communityCount
                if ($scope.reportingData[community] == null)
                    $scope.reportingData[community] = {}
                initCommunityDisplay(community, date)
            }
            if ($scope.reportingData[community][date] == null)
                $scope.reportingData[community][date] = {}

            if (column == null) {
                var len = $scope.displayedColumns.length
                for (var i = 0; i < len; i++) {
                    $("#" + community).append("<td id='" + $scope.displayedColumns[i].split("$")[2] + "data" + communityIndex[community] + "'></td>")
                    getColumnDataAPI(community, date, $scope.displayedColumns[i])
                }
                return;
            }

            var i = $scope.displayedColumns.indexOf(column);
            if (i == -1) addColumn(column)

            //$("#rowDate").html($compile("{{data['" + date + "']}}")(scope))
            getSelectedCommunityData(date, column)
        }

        //$scope.getReport('all')

        /** GET COLUMN DATA */
        function getColumnDataAPI(comm, date, column) {
            var datatype = column.split("$")[2]
            var id = "#" + datatype + "data" + communityIndex[comm]

            $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getReport/' + comm + '/' + date + '/' + column + '/' + interval, {
                headers: {'Content-Type': 'application/json;charset=utf-8'}
            }).success(function (data) {
                if (datatype.indexOf("new") > -1 || datatype == 'activeusers') {
                    if ($scope.reportingData[comm][date][datatype] == null)
                        $scope.reportingData[comm][date][datatype] = {}
                    $scope.reportingData[comm][date][datatype][intervaltext] = data.data
                    $(id).html($scope.reportingData[comm][date][datatype][intervaltext])
                } else {
                    $scope.reportingData[comm][date][datatype] = data.data
                    $(id).html($scope.reportingData[comm][date][datatype])
                }
            }).error(function () {
            });
        }

        $scope.getNewDateReport = function (date) {
            var date = date == null || date == '' ? new Date().format("yyyy-MM-dd") : date
            $scope.date = date

            for (c in communityIndex) {
                $("#date" + communityIndex[c]).html(date)

                if ($scope.reportingData[c][date] == null) {
                    $scope.reportingData[c][date] = {}
                    var len = $scope.displayedColumns.length;
                    for (var i = 0; i < len; i++)
                        getColumnDataAPI(c, date, $scope.displayedColumns[i])
                } else {
                    var len = $scope.displayedColumns.length;
                    for (var i = 0; i < len; i++) {
                        var datatype = $scope.displayedColumns[i].split("$")[2]
                        var id = "#" + datatype + "data" + communityIndex[c]
                        if ($scope.reportingData[c][date][datatype] == null) {
                            getColumnDataAPI(c, date, $scope.displayedColumns[i])
                        } else {
                            if (datatype.indexOf("new") > -1 || datatype == 'activeusers') {
                                if ($scope.reportingData[c][date][datatype][intervaltext] == null)
                                    getColumnDataAPI(c, date, $scope.displayedColumns[i])
                                else
                                    $(id).html($scope.reportingData[c][date][datatype][intervaltext])
                            } else
                                $(id).html($scope.reportingData[c][date][datatype])
                        }
                    }
                }
            }
        }

        $scope.setDateInterval = function (setinterval) {
            interval = setinterval
            intervaltext = setinterval == 7 ? 'week' : 'day'

            var len = $scope.displayedColumns.length;
            for (var i = 0; i < len; i++) {
                var datatype = $scope.displayedColumns[i].split("$")[2]
                if (datatype.indexOf("new") > -1 || datatype == 'activeusers') {
                    for (comm in communityIndex) {
                        var id = "#" + datatype + "data" + communityIndex[comm]
                        if ($scope.reportingData[comm][$scope.date][datatype] == null)
                            $scope.reportingData[comm][$scope.date][datatype] = {}
                        if ($scope.reportingData[comm][$scope.date][datatype][intervaltext] == null)
                            getColumnDataAPI(comm, $scope.date, $scope.displayedColumns[i])
                        else
                            $(id).html($scope.reportingData[comm][$scope.date][datatype][intervaltext])
                    }
                }
            }
        }


        /** GET DATA FROM COMMUNITIES THAT WERE SELECTED */
        function getSelectedCommunityData(date, column) {
            var datatype = column.split("$")[2]

            for (c in communityIndex) {
                var id = datatype + "data" + communityIndex[c]
                if ($("#" + id).length == 0)
                    $("#" + c).append("<td id='" + id + "'></td>")
                if ($scope.reportingData[c][date][datatype] == null) {
                    getColumnDataAPI(c, date, column)
                } else {
                    if (datatype.indexOf("new") > -1 || datatype == 'activeusers') {
                        if ($scope.reportingData[c][date][datatype][intervaltext] == null) getColumnDataAPI(c, date, column)
                        else $("#" + id).html($scope.reportingData[c][date][datatype][intervaltext])
                    } else $("#" + id).html($scope.reportingData[c][date][datatype])
                }
            }
        }

        //$scope.communityToggle = function (community, date) {
        //    if (community in communityIndex)
        //        removeCommunity(community);
        //    else
        //        $scope.getReport(community, date)
        //}

        //function removeCommunity(community) {
        //    $("#" + community).remove()
        //    delete communityIndex[community]
        //}

        $scope.columnToggle = function (community, date, column) {
            var idx = $scope.displayedColumns.indexOf(column);
            if (idx > -1) removeColumn(column);
            else $scope.getReport(community, date, column)
        };

        function addColumn(column) {
            var datatype = column.split("$")[2]
            $("#columndisplay").append("<th id='" + datatype + "'>" + $scope.columns[column] + "</th>")
            $scope.displayedColumns.push(column)
        }

        function removeColumn(column) {
            var i = $scope.displayedColumns.indexOf(column);
            if (i == -1) return
            $scope.displayedColumns.splice(i, 1);
            var datatype = column.split("$")[2]
            var columnId = "#" + datatype
            var columnDataId = columnId + "data"
            $(columnId).remove()    // remove column header
            for (var i = 0; i <= communityCount; i++)      // remove column rows
                $(columnDataId + i).remove()
        }

        function getCommName(commId) {
            if (commId == 'all')
                return allCommName
            var commName = ''
            var len = $scope.communityList.length;
            for (var i = 0; i < len; i++) {
                if ($scope.communityList[i].objId == commId) {
                    commName = $scope.communityList[i].communityName
                    break
                }
            }
            return commName
        }


        /** ====================================== RETENTION PAGE ======================================  */

        $scope.commsInRetention = {}

        graphFunctions.retention = {    // graph is a combo of line and column i.e. consists of a primary and a secondary y axis
            initRetentionGraphs: function (graphObj) {
                dataGraph[graphObj] = {data: createComboGraphTemplate()}

                // Config chart renderTo
                var graphName = graphObj + 'Chart'
                dataGraph[graphObj].data.chart.renderTo = graphName

                var titleName = 'Weekly Retention'
                if (graphObj.indexOf('monthly') > -1)
                    titleName = 'Monthly Retention'

                // Config title
                dataGraph[graphObj].data.title.text = titleName + " (%) (Weighted Average) vs Users"

                // Config primary yAxis title and labels
                dataGraph[graphObj].data.yAxis[0].title.text = titleName + " (%)"
                dataGraph[graphObj].data.yAxis[0].labels.format = "{value}%"

                // Config secondary yAxis title and labels
                dataGraph[graphObj].data.yAxis[1].title.text = 'Users'
                dataGraph[graphObj].data.yAxis[1].labels.format = "{value}"
            },
            xAxis: {
                pushXAxisCategoryToRetentionGraph: function (graph, category) {
                    dataGraph[graph].data.xAxis[0].categories.push(category)
                }
            },
            series: {
                pushPrimaryDataToRetentionGraph: function (graph, seriesName, seriesPrimaryDataArray) {
                    var graphRef = dataGraph[graph].data
                    var len = graphRef.series.length
                    var idx = Math.floor(len / 2)
                    for (var i = 0; i < len; i++) {
                        if (seriesName === graphRef.series[i].name && 'spline' === graphRef.series[i].type) {
                            if (Object.prototype.toString.call(seriesPrimaryDataArray) === '[object Array]') {
                                seriesPrimaryDataArray.forEach(function (item) {
                                    graphRef.series[i].data.push(item)
                                })
                            }
                            return
                        }
                    }
                    var newSeriesPrimary = {
                        name: seriesName,
                        type: 'spline',
                        color: getGraphSeriesColor(idx),
                        tooltip: {valueSuffix: '%'},
                        data: []
                    }
                    if (Object.prototype.toString.call(seriesPrimaryDataArray) === '[object Array]') {
                        seriesPrimaryDataArray.forEach(function (item) {
                            newSeriesPrimary.data.push(item)
                        })
                    }
                    graphRef.series.push(newSeriesPrimary)
                },
                pushSecondaryDataToRetentionGraph: function (graph, seriesName, seriesSecondaryDataArray) {
                    var graphRef = dataGraph[graph].data
                    var len = graphRef.series.length
                    var idx = Math.floor(len / 2)
                    for (var i = 0; i < len; i++) {
                        if (seriesName === graphRef.series[i].name && 'column' === graphRef.series[i].type) {
                            if (Object.prototype.toString.call(seriesSecondaryDataArray) === '[object Array]') {
                                seriesSecondaryDataArray.forEach(function (item) {
                                    graphRef.series[i].data.push(item)
                                })
                            }
                            return
                        }
                    }
                    var newSeriesSecondary = {
                        name: seriesName,
                        type: 'column',
                        yAxis: 1,
                        color: getGraphSeriesColor(idx),
                        tooltip: {valueSuffix: ''},
                        data: []
                    }
                    if (Object.prototype.toString.call(seriesSecondaryDataArray) === '[object Array]') {
                        seriesSecondaryDataArray.forEach(function (item) {
                            newSeriesSecondary.data.push(item)
                        })
                    }
                    graphRef.series.push(newSeriesSecondary)
                },
                resetAllDataInRetentionGraphs: function () {
                    for (var i = 0; i < dataGraph['weeklyRetention'].data.series.length; i++) {
                        dataGraph['weeklyRetention'].data.series[i].data = []
                    }
                    for (var i = 0; i < dataGraph['monthlyRetention'].data.series.length; i++) {
                        dataGraph['monthlyRetention'].data.series[i].data = []
                    }
                },
                removeCommInRetentionGraphs: function (commName) {
                    for (var i = 0; i < dataGraph['weeklyRetention'].data.series.length; i++) {
                        if (dataGraph['weeklyRetention'].data.series[i].name === commName) {
                            dataGraph['weeklyRetention'].data.series.splice(i, 1)   // 删除 primary data
                            dataGraph['weeklyRetention'].data.series.splice(i, 1)   // 删除 secondary data
                        }
                    }
                    for (var i = 0; i < dataGraph['monthlyRetention'].data.series.length; i++) {
                        if (dataGraph['monthlyRetention'].data.series[i].name === commName) {
                            dataGraph['monthlyRetention'].data.series.splice(i, 1)  // 删除 primary data
                            dataGraph['monthlyRetention'].data.series.splice(i, 1)   // 删除 secondary data
                        }
                    }
                },
            }
        }

        $scope.retentionData = {weekly: {}, monthly: {}}
        // $scope.retentionData.weekly = {comm1: {userBatchDate1: {totalUsers: 500, data : {week1:{active: 250, retentionRate: 50%}, week2:{active: 100, retentionRate: 20%}, ...}}, userBatchDate2: {totalUsers: 100, data: {week1:{}}, ...}, ...}, comm2: {...}, ...}
        // $scope.retentionData.weekly['comm1'][userBatchDate1]['totalUsers'] = 500
        // $scope.retentionData.weekly['comm1'][userBatchDate1].data['week2']['active'] = 100

        //var retentionCommunityCount = -1

        $scope.getRetentionReport = function (community) {

            if (community == null)
                community = 'all'

            if ($scope.commsInRetention[community])
                return
            $scope.commsInRetention[community] = getCommName(community)

            if ($scope.retentionData.weekly[community] == null)
                $scope.retentionData.weekly[community] = {}
            retention(community, 'weekly')

            if ($scope.retentionData.monthly[community] == null)
                $scope.retentionData.monthly[community] = {}
            retention(community, 'monthly')
        }

        function retention(community, interval) {
            var timeColumn = interval + 'Column'
            var graphName = interval + 'Retention'
            var len = $scope[timeColumn].length
            for (var i = 0; i < len; i++) {
                graphFunctions.retention.xAxis.pushXAxisCategoryToRetentionGraph(graphName, $scope[timeColumn][i])
            }
            if (checkIfRetentionDataForCommExists(community, interval)) {
                weightedAverageRetention(community, interval)
                displayGraph(interval + 'Retention')
            } else {
                var promise = $http.get('http://' + backOfficeHost + '/rest/v1.0/backoffice/reports/getRetentionByComm/' + community + '/' + interval, {
                    headers: {'Content-Type': 'application/json;charset=utf-8'}
                }).then(function (data) {
                    var len = data.data.data.length
                    for (var i = 0; i < len; i++) {
                        var d = data.data.data[i]
                        var batchDate = d['batchDate']
                        var retentionPeriod = d['retentionPeriod']
                        if ($scope.retentionData[interval][community][batchDate] == null)
                            $scope.retentionData[interval][community][batchDate] = {data: {}}
                        $scope.retentionData[interval][community][batchDate]['totalUsers'] = d['totalUsers']
                        $scope.retentionData[interval][community][batchDate].data[retentionPeriod] = {}
                        $scope.retentionData[interval][community][batchDate].data[retentionPeriod]['retentionRate'] = d['retentionRate']
                        $scope.retentionData[interval][community][batchDate].data[retentionPeriod]['activeUsers'] = d['activeUsers']
                    }
                    return 'success'
                });
                promise.then(function (data) {
                    fillInBlankRetentionData(community, interval)
                    $scope.retentionData[interval][community] = sortOnKeys($scope.retentionData[interval][community])
                    weightedAverageRetention(community, interval)
                    displayGraph(interval + 'Retention')
                })
            }
        }

        function fillInBlankRetentionData(community, interval) {
            var timeColumn = $scope[interval + 'Column']
            var len = timeColumn.length
            for (var i = 0; i < len; i++) {
                var batchDate = timeColumn[i]
                if ($scope.retentionData[interval][community][batchDate] == null) {
                    $scope.retentionData[interval][community][batchDate] = {totalUsers : 0, data:{}}
                    //$scope.retentionData[interval][community][batchDate] = {totalUsers: 0}
                }
                //else{
                //    totalUsers += $scope.retentionData[interval][community][batchDate]['totalUsers']
                //}
            }
        }

        function checkIfRetentionDataForCommExists(community, interval) {
            var timeColumn = $scope[interval + 'Column']
            var len = timeColumn.length
            for (var i = 0; i < len; i++) {
                var batchDate = timeColumn[i]
                if ($scope.retentionData[interval][community][batchDate] == null) {
                    return false
                }
            }
            return true
        }

        function weightedAverageRetention(community, interval) {
            var graphName = interval + 'Retention'
            var graphStartDate = $scope[interval + 'Column'][0]
            var commName = getCommName(community)

            var today = new Date()
            var prevPeriod = newIncrementDate(today, -7)

            if (interval === 'monthly')
                prevPeriod = new Date(today.setMonth(new Date(today).getMonth() - 1))
            var totalUsers = 0;
            var retentionRate = 0;

            var count = 0
            for (batch in $scope.retentionData[interval][community]) {
                var idx = count++

                if (batch > prevPeriod)
                    continue
                var newUserBatch = $scope.retentionData[interval][community][batch]['totalUsers']
                var previousTotalUsers = totalUsers
                totalUsers += newUserBatch
                if (totalUsers == 0)
                    continue
                var batchRetentionDate = newIncrementDate(batch, 7)
                if (interval === 'monthly')
                    batchRetentionDate = new Date(new Date(batch).setMonth(new Date(batch).getMonth() + 1))
                var batchRetentionRate = 0
                if ($scope.retentionData[interval][community][batch].data[batchRetentionDate.format('yyyy-MM-dd')] != null)
                    batchRetentionRate = $scope.retentionData[interval][community][batch].data[batchRetentionDate.format('yyyy-MM-dd')]['retentionRate']
                retentionRate = retentionRate * previousTotalUsers / totalUsers + batchRetentionRate * newUserBatch / totalUsers;

                var idx1 = 0
                var idx2 = 0
                if(interval === 'weekly'){
                    idx1 = Math.floor(getDayDiff(batch, graphStartDate)/7)
                    idx2 = Math.floor(getDayDiff(batchRetentionDate, graphStartDate)/7)
                }
                else if(interval === 'monthly'){
                    graphStartDate = new Date(graphStartDate)
                    idx1 = new Date(batch).getMonth() - graphStartDate.getMonth() + (12 * (new Date(batch).getFullYear() - graphStartDate.getFullYear()))
                    idx2 = batchRetentionDate.getMonth() - graphStartDate.getMonth() + (12 * (batchRetentionDate.getFullYear() - batchRetentionDate.getFullYear()))
                }

                graphFunctions.retention.series.pushSecondaryDataToRetentionGraph(graphName, commName, [[idx1, totalUsers]])
                if(batchRetentionDate < prevPeriod)
                    graphFunctions.retention.series.pushPrimaryDataToRetentionGraph(graphName, commName, [[idx2, Math.round((retentionRate * 100) * 100) / 100]])
            }
        }

        $scope.refreshRetentionRates = function () {
            graphFunctions.retention.series.resetAllDataInRetentionGraphs()
            for (comm in $scope.commsInRetention) {
                weightedAverageRetention(comm, 'weekly')
                weightedAverageRetention(comm, 'monthly')
            }
            displayGraph('weeklyRetention')
            displayGraph('monthlyRetention')
        }

        $scope.removeCommInRetention = function (community) {
            delete $scope.commsInRetention[community]
            graphFunctions.retention.series.removeCommInRetentionGraphs(getCommName(community))
            $scope.refreshRetentionRates()
        }


        /** ============================================================================  */


        /** PAGE INIT */
        function initReportPage() {
            //var community = 'all'
            $scope.date = new Date().format("yyyy-MM-dd")

            getDistrictListAPI()

            // GRAPH INIT
            graphFunctions.initMainGraphs()
            $scope.getGraph('all')

            function getDistrictListAPI() {
                $http.get('http://' + backOfficeHost + '/rest/v1.0/communities/getAllCommunityGroups', {
                    headers: {'Content-Type': 'application/json;charset=utf-8'}
                }).success(function (data) {
                    var len = data.data.length
                    for (var i = 0; i < len; i++)
                        $scope.districtList.push(data.data[i])
                }).error(function () {
                });
            }
        }

        initReportPage()


        /** STATS PAGE INIT */
        var statsPageClicks = 0;
        $scope.initStatsPage = function () {
            if (statsPageClicks == 0) {
                $scope.getReport('all')
                showDisplayedColumns()
            }
            statsPageClicks++;
            function showDisplayedColumns() {
                for (k in $scope.columns) {
                    $("#columndisplay").append("<th id='" + k.split('$')[2] + "'>" + $scope.columns[k] + "</th>")
                }
            }
        }

        /** RETENTION PAGE INIT */
        var retentionPageClicks = 0;
        $scope.initRetentionPage = function () {
            if (retentionPageClicks == 0) {
                graphFunctions.retention.initRetentionGraphs('weeklyRetention')
                graphFunctions.retention.initRetentionGraphs('monthlyRetention')
                $scope.getRetentionReport('all')
                $("#retentionStart").html(onlineDate)
                $("#retentionEnd").html(new Date().format('yyyy-MM-dd'))
            }
            else {
                $scope.refreshRetentionRates()
            }
            retentionPageClicks++;
        }

        var mainPageClicks = 0;
        $scope.reInitMainPage = function () {
            if (mainPageClicks == 0) {
                $scope.refreshMainGraphs()
            } else {

            }
            mainPageClicks++
        }


        $scope.printOut = function () {
            //console.info($scope.testdata)
            //$("#aaa").html($compile($scope.date)($scope))
            //console.info($scope.reportingData)
            console.log($scope.retentionData)
        }

    }])